# file:    yamltunes.rb
# author:  davidfmiller http://www.fivevoltlogic.com/code/mytunes/yaml
# version: v0.1b
# about:   a class that accepts yamltunes markup and excutes the corresponding AppleScript
#          to create/update the playlist(s) in itunes
#
# ---
# "d.new":
#  - buck 65 : blood of a young wolf
#  - jason collett : hangover days
# 
# porno:
#  - a.c. newman : the town halo
#  - the new pornographers : twin cinema
# ...
#
# history: v0.1 august 25, 2005
#           - initial version complete
#
#          v0.1.1 march 10, 2006
#           - works with "odd" characters like diacriticals, etc.
#

require 'yaml'
require 'applescript'

class YAMLTunes

	# the yaml tree
	@tree = nil

	# the name of the folder where the playlist should be created in itunes (defaults to the top-level) CURRENTLY UNSUPPORTTED
	@folder = nil

	# yaml should either by a file object whose contents is yaml, or a string that contains yaml formatting
	def initialize(yaml)

		if (yaml.class == File)
			yaml = yaml.read
		end
		
		@tree = YAML::parse(yaml).transform

#		@folder = folder
	end	

	# process the yaml, creating the playlists in itunes
	def run
		appl = AppleScript.new(build_script()).run
	end
	
	private
	def escape(arg)
		'"' + arg.to_s.gsub(/"/, '\"')  + '"' #.dump
	end
	
	
	# method that does all of the grunt work of walking through the structure parsed by the yaml code 
	# and generating the AppleScript code from it 
	#
	def build_script

		# if a folder name is specified, make sure it exists
		buffer = @folder ? '
			set myfolders to every folder playlist whose name is ' + escape(@folder) + '
			if (length of myfolders is 0) then
				(* if no folders exist with that name, then create it *)
				set myfolder to make new folder playlist with properties {name: ' + escape(@folder) + '}
			else
			  (* if atleast *one* folder already exists with that name, then use the first one stumble across *)
				set myfolder to item 1 of myfolders
			end if 
		' : ''

		# for each playlist and track, try to add the track to its corresponding playlist
		@tree.each do |p|

			playlist = p[0] # get the playlist name

			# don't worry about smart playlists and podcasts, since we can't manually (er, programmatically) add tracks to them 
			buffer += '
				(* make sure the playlist exists *)
				set mylists to (every playlist whose name is ' + escape(playlist) + ' and smart is false and special kind is not Podcasts)
				set p to false

				(* if the playlist exists then delete it, so that we\'ll have a fresh start *)
				if (length of mylists is 1) then
					delete item 1 of mylists
				end if

				set p to make new playlist with properties {name: ' + escape(playlist) + (@folder ? ', parent: myfolder' : '') + '}
			'

			p[1].each do |t| # add each track to the playlist
				track = t.shift
				buffer += "
					set t to my getTrack(" + escape(track[0]) + ", " + escape(track[1]) + ")
					if (t is not false) then
						try
							duplicate t to p
						on error e
						end try
					end if
					"
			end 
		end

		# return the generated AppleScript
		buffer_prefix + buffer + buffer_suffix
	end

	# return any AppleScript code that should be placed *before* the code required to create the playlist(s)
	def buffer_prefix
		'on getTrack(myArtist, myTrack)
		 tell application "iTunes"
		 ignoring case and diacriticals and punctuation and white space
		  set r to every track of playlist 1 whose artist is myArtist and name is myTrack
		 end considering
		 if (length of r is greater than 0)
		  return item 1 of r
		 else
		  return false
		 end if
		 end tell
		end

		tell application "iTunes"
		'
	end
	
	# return any AppleScript code that should be placed *after* the code required to create the playlist(s)
	def buffer_suffix
		'
			set view of window 1 to p
		end tell
		'
	end
	
end